#include <ptgui/ptgui.h>
#include <ptgui/image.h>
#include <ptgui/filerw.h>
#include <ptgui/image_xpm.h>
#include <ptgui/image_hdc.h>

static ptgui_list_t _ptgui_system_image_list =
{
	RT_NULL
};

/* init ptgui image system */
void ptgui_image_system_init(void)
{
	/* always support XPM image */
	ptgui_image_xpm_init();
	ptgui_image_hdc_init();
}

static struct ptgui_image_engine * ptgui_image_get_engine(const char *type)
{
	struct ptgui_list_node *node;
	struct ptgui_image_engine *engine;

	ptgui_list_foreach(node, &_ptgui_system_image_list)
	{
		engine = ptgui_list_entry(node, struct ptgui_image_engine, list);

		if (ptgui_strncasecmp(engine->name, type, ptgui_strlen(engine->name)) == 0) {
			return engine;
		}
	}

	return RT_NULL;
}

struct ptgui_image * ptgui_image_create_from_file(const char *type, const char *filename, rt_bool_t load)
{
	struct ptgui_filerw *filerw;
	struct ptgui_image_engine *engine;
	struct ptgui_image *image = RT_NULL;

	/* create filerw context */
	filerw = ptgui_filerw_create_file(filename, "rb");
	if (filerw == RT_NULL) {
		return RT_NULL;
	}

	/* get image engine */
	engine = ptgui_image_get_engine(type);
	if (engine == RT_NULL) {
		/* close filerw context */
		ptgui_filerw_close(filerw);
		return RT_NULL;
	}

	if (engine->image_check(filerw) == RT_TRUE) {
		image = (struct ptgui_image *)ptgui_malloc(sizeof(struct ptgui_image));
		if (image == RT_NULL) {
			/* close filerw context */
			ptgui_filerw_close(filerw);
			return RT_NULL;
		}

		if (engine->image_load(image, filerw, load) != RT_TRUE) {
			/* close filerw context */
			ptgui_filerw_close(filerw);
			return RT_NULL;
		}

		/* set image engine */
		image->engine = engine;
		image->refs = 1;
	}
	else {
		ptgui_filerw_close(filerw);
	}

	return image;
}

struct ptgui_image * ptgui_image_create_from_mem(const char *type, const rt_uint8_t *data, rt_size_t length,
												 rt_bool_t load)
{
	struct ptgui_filerw *filerw;
	struct ptgui_image_engine *engine;
	struct ptgui_image *image = RT_NULL;

	/* create filerw context */
	filerw = ptgui_filerw_create_mem(data, length);
	if (filerw == RT_NULL) {
		return RT_NULL;
	}

	/* get image engine */
	engine = ptgui_image_get_engine(type);
	if (engine == RT_NULL) {
		/* close filerw context */
		ptgui_filerw_close(filerw);
		return RT_NULL;
	}

	if (engine->image_check(filerw) == RT_TRUE) {
		image = (struct ptgui_image *)ptgui_malloc(sizeof(struct ptgui_image));
		if (image == RT_NULL) {
			/* close filerw context */
			ptgui_filerw_close(filerw);
			return RT_NULL;
		}

		if (engine->image_load(image, filerw, load) != RT_TRUE) {
			/* close filerw context */
			ptgui_filerw_close(filerw);
			return RT_NULL;
		}

		/* set image engine */
		image->engine = engine;
		image->refs = 1;
	}
	else {
		ptgui_filerw_close(filerw);
	}

	return image;
}

void ptgui_image_destroy(struct ptgui_image *image)
{
	RT_ASSERT(image != RT_NULL);

	image->refs--;
	if (image->refs) {
		return;
	}

	image->engine->image_unload(image);
	ptgui_free(image);
}

/* register an image engine */
void ptgui_image_register_engine(struct ptgui_image_engine *engine)
{
	RT_ASSERT(engine != RT_NULL);

	ptgui_list_append(&_ptgui_system_image_list, &(engine->list));
}

void ptgui_image_blit(struct ptgui_image *image, struct ptgui_dc *dc, struct ptgui_rect *rect)
{
	RT_ASSERT(dc != RT_NULL);
	RT_ASSERT(rect != RT_NULL);

	if (ptgui_dc_get_visible(dc) != RT_TRUE) {
		return;
	}

	if (image != RT_NULL && image->engine != RT_NULL) {
		/* use image engine to blit */
		image->engine->image_blit(image, dc, rect);
	}
}

